package com.example.redisjson.service.impl;

import com.example.redisjson.documents.Company;
import com.example.redisjson.documents.CompanyMeta;
import com.example.redisjson.documents.Person;
import com.example.redisjson.documents.UserDocument;
import com.example.redisjson.repositories.json.UserRepository;
import com.example.redisjson.repositories.search.CompanyRepository;
import com.example.redisjson.repositories.search.PersonRepository;
import com.redis.om.spring.search.stream.EntityStream;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.data.geo.Point;
import org.springframework.stereotype.Service;
import redis.clients.jedis.search.aggr.SortedField;

import java.util.Set;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class UserServiceImpl {

    private final EntityStream entityStream;
    private final UserRepository userRepository;

    // Find people by age range
    public Iterable<UserDocument> findByAgeBetween(int minAge, int maxAge) {
        return entityStream //
                .of(Person.class) //
                .filter(Person$.AGE.between(minAge, maxAge)) //
                .sorted(Person$.AGE, SortedField.SortOrder.ASC) //
                .collect(Collectors.toList());
    }

    @Resource
    CompanyRepository companyRepo;

    @Resource
    PersonRepository personRepo;

    @Bean
    CommandLineRunner loadTestData() {
        return args -> {
            companyRepo.deleteAll();
            Company redis = Company
                    .of("Redis", "https://redis.com", new Point(-122.066540, 37.377690), 526, 2011,
                    Set.of(CompanyMeta.of("Redis", 100, Set.of("RedisTag"))));
            redis.setTags(Set.of("fast", "scalable", "reliable"));

            Company microsoft = Company
                    .of("Microsoft", "https://microsoft.com", new Point(-122.124500, 47.640160), 182268,
                    1975, Set.of(CompanyMeta.of("MS", 50, Set.of("MsTag"))));
            microsoft.setTags(Set.of("innovative", "reliable"));

            companyRepo.save(redis);
            companyRepo.save(redis); // save again to test @LastModifiedDate
            companyRepo.save(microsoft);

            personRepo.deleteAll();
            personRepo.save(Person.of("Brian", "Sam-Bodden", "bsb@redis.com"));
            personRepo.save(Person.of("Guy", "Royse", "guy.royse@redis.com"));
            personRepo.save(Person.of("Guy", "Korland", "guy.korland@redis.com"));
        };
    }

}

/*
使用实体流进行流畅搜索
    Redis OM Spring 实体流提供了一个 Java 8 流接口，用于使用 Redis Stack 查询 Redis JSON 文档。
    实体流允许您以类似于 SQL 语句的类型安全声明方式处理数据。流可用于将查询表达为一系列操作。

    Redis OM Spring 中的实体流提供与 Java 8 流相同的语义。流可以由 Redis 映射实体（@Document）或实体的一个或多个属性组成。
    实体流逐步构建查询，直到调用终止操作（例如collect）。每当对流应用终止操作时，流就不能再接受其管道中的其他操作，这意味着流已启动。

实体元模型
    您将获得一个生成的元模型来生成更复杂的查询，该类与您的模型同名，但以美元符号结尾。在下面的示例中，我们的实体模型是 Person；因此，我们得到一个名为 Person$ 的元模型。
    使用元模型，您可以访问底层搜索引擎字段操作。例如，我们有一个 age 属性，它是一个整数。因此，我们的元模型具有一个 AGE 属性，该属性具有我们可以与流的 filter 方法一起使用的数字操作，
*/